package front.end.subestacao.ui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Paint;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.geom.Point2D;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.JInternalFrame;
import javax.swing.JPanel;

import org.apache.commons.collections15.Transformer;

import edu.uci.ics.jung.algorithms.layout.FRLayout;
import edu.uci.ics.jung.algorithms.layout.ISOMLayout;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.samples.LensVertexImageShaperDemo;
import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
import edu.uci.ics.jung.visualization.LayeredIcon;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
import edu.uci.ics.jung.visualization.control.ModalGraphMouse;
import edu.uci.ics.jung.visualization.control.SatelliteVisualizationViewer;
import edu.uci.ics.jung.visualization.control.ScalingControl;
import edu.uci.ics.jung.visualization.decorators.DefaultVertexIconTransformer;
import edu.uci.ics.jung.visualization.decorators.EllipseVertexShapeTransformer;
import edu.uci.ics.jung.visualization.decorators.PickableEdgePaintTransformer;
import edu.uci.ics.jung.visualization.decorators.PickableVertexPaintTransformer;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
import edu.uci.ics.jung.visualization.decorators.VertexIconShapeTransformer;
import edu.uci.ics.jung.visualization.layout.CachingLayout;
import edu.uci.ics.jung.visualization.picking.PickedState;
import edu.uci.ics.jung.visualization.renderers.Checkmark;
import edu.uci.ics.jung.visualization.renderers.DefaultEdgeLabelRenderer;
import edu.uci.ics.jung.visualization.renderers.DefaultVertexLabelRenderer;
import edu.uci.ics.jung.visualization.renderers.Renderer;
import edu.uci.ics.jung.visualization.transform.LayoutLensSupport;
import edu.uci.ics.jung.visualization.transform.LensSupport;
import edu.uci.ics.jung.visualization.transform.shape.MagnifyImageLensSupport;
import front.end.subestacao.constants.SystemConstants;
import front.end.subestacao.itens.Componente;
import front.end.subestacao.rede.Ligacao;

public class PainelVisual {

	private Graph<Componente, Ligacao> grafo;

	private String nome;

	private VisualizationViewer<Componente, Ligacao> vv1;

	private VisualizationViewer<Componente, Ligacao> satellite;

	private VisualizationViewer<Componente, Ligacao> vv2;

	private CachingLayout<Componente, Ligacao> cl1;

	private CachingLayout<Componente, Ligacao> cl2;

	// a Map for the labels
	Map<Componente, String> map = new HashMap<Componente, String>();

	// a Map for the Icons
	Map<Componente, Icon> iconMap = new HashMap<Componente, Icon>();

	JInternalFrame represPainel;

	JInternalFrame represPainelIcon;

	LensSupport viewSupport;
	LensSupport modelSupport;
	LensSupport magnifyLayoutSupport;
	LensSupport magnifyViewSupport;
	
	FrontEndSubView viewPrinc;

	public PainelVisual(String nome, Graph<Componente, Ligacao> grafo, FrontEndSubView viewPrinc) {
		this.viewPrinc = viewPrinc;
		this.grafo = grafo;

		this.nome = nome;

		inicializaMaps();

		criaVV1();
		criaVV2();

	}

	private void inicializaMaps() {
		for (Componente componente : grafo.getVertices()) {
			map.put(componente, componente.toString());

			// String name = SystemConstants.SYSTEM_ICONE_DIRECTORY +
			// componente.getNomeIcone();

			try {

				File dirImagens = new File(
						SystemConstants.SYSTEM_ICONE_DIRECTORY);
				File[] arquivos = dirImagens.listFiles();

				File arqImg = null;
				for (File arq : arquivos) {
					StringTokenizer nomeArqBuf = new StringTokenizer(arq
							.getName(), ".");
					String nomeSemExtensao = nomeArqBuf.nextToken();
					if (nomeSemExtensao == null) {
						nomeSemExtensao = arq.getName();
					}

					if (nomeSemExtensao.equalsIgnoreCase(componente.getNomeIcone())) {
						arqImg = arq;
					}

				}

				Image img = new ImageIcon(arqImg.getCanonicalPath()).getImage();

				Image newimg = img.getScaledInstance(60, 60,
						java.awt.Image.SCALE_SMOOTH);

				Icon icon = new LayeredIcon(newimg);

				iconMap.put(componente, icon);
			} catch (Exception ex) {
				ex.printStackTrace();

			}
		}
	}

	private void criaVV2() {

		FRLayout<Componente, Ligacao> layout = new FRLayout<Componente, Ligacao>(
				grafo);
		layout.setMaxIterations(100);
		vv2 = new VisualizationViewer<Componente, Ligacao>(layout,
				new Dimension(600, 600));

		Transformer<Componente, Paint> vpf = new PickableVertexPaintTransformer<Componente>(
				vv2.getPickedVertexState(), Color.white, Color.yellow);

		vv2.getRenderContext().setVertexFillPaintTransformer(vpf);
		vv2.getRenderContext().setEdgeDrawPaintTransformer(
				new PickableEdgePaintTransformer<Ligacao>(vv2
						.getPickedEdgeState(), Color.black, Color.cyan));

		vv2.setBackground(Color.white);

		final Transformer<Componente, String> vertexStringerImpl = new VertexStringerImpl<Componente>(
				map);

		vv2.getRenderContext().setVertexLabelTransformer(vertexStringerImpl);
		vv2.getRenderContext().setVertexLabelRenderer(
				new DefaultVertexLabelRenderer(Color.cyan));
		vv2.getRenderContext().setEdgeLabelRenderer(
				new DefaultEdgeLabelRenderer(Color.cyan));

		// features on and off. For a real application, use
		// VertexIconAndShapeFunction instead.
		final VertexIconShapeTransformer<Componente> vertexImageShapeFunction = new VertexIconShapeTransformer<Componente>(
				new EllipseVertexShapeTransformer<Componente>());

		final DefaultVertexIconTransformer<Componente> vertexIconFunction = new DefaultVertexIconTransformer<Componente>();

		vertexImageShapeFunction.setIconMap(iconMap);
		vertexIconFunction.setIconMap(iconMap);

		vv2.getRenderContext().setVertexShapeTransformer(
				vertexImageShapeFunction);
		vv2.getRenderContext().setVertexIconTransformer(vertexIconFunction);

		PickedState<Componente> ps = vv2.getPickedVertexState();

		ps.addItemListener(new PickWithIconListener(vertexIconFunction));

		vv2.addPostRenderPaintable(new VisualizationViewer.Paintable() {
			int x;
			int y;
			Font font;
			FontMetrics metrics;
			int swidth;
			int sheight;
			String str = "Front End Subestacao";

			public void paint(Graphics g) {
				Dimension d = vv2.getSize();
				if (font == null) {
					font = new Font(g.getFont().getName(), Font.BOLD, 20);
					metrics = g.getFontMetrics(font);
					swidth = metrics.stringWidth(str);
					sheight = metrics.getMaxAscent() + metrics.getMaxDescent();
					x = (d.width - swidth) / 2;
					y = (int) (d.height - sheight * 1.5);
				}
				g.setFont(font);
				Color oldColor = g.getColor();
				g.setColor(Color.lightGray);
				g.drawString(str, x, y);
				g.setColor(oldColor);
			}

			public boolean useTransform() {
				return false;
			}
		});

		// add a listener for ToolTips
		vv2.setVertexToolTipTransformer(new ToStringLabeller<Componente>());

		final DefaultModalGraphMouse<Componente, Ligacao> graphMouse = new DefaultModalGraphMouse<Componente, Ligacao>();
		graphMouse.setMode(ModalGraphMouse.Mode.PICKING);
		vv2.setGraphMouse(graphMouse);

		cl2 = new CachingLayout<Componente, Ligacao>(vv2.getGraphLayout());
		cl2.init();

		inicializaPosicoes(true);
		geraRepresPainelIcon();

	}

	private void criaVV1() {

		ModalGraphMouse graphMouse;

		Componente comp = new Componente();
		comp.setNome("sdfasd");

		grafo.addVertex(comp);

		Layout<Componente, Ligacao> layout = new ISOMLayout<Componente, Ligacao>(
				grafo);

		vv1 = new VisualizationViewer<Componente, Ligacao>(layout,
				new Dimension(600, 600));

		vv1.getRenderContext().setEdgeDrawPaintTransformer(
				new PickableEdgePaintTransformer<Ligacao>(vv1
						.getPickedEdgeState(), Color.black, Color.cyan));

		// vv.getRenderContext().setEdgeShapeTransformer(new
		// EdgeShape.Line<Componente,Fusao>());

		vv1.getRenderContext().setVertexFillPaintTransformer(
				new PickableVertexPaintTransformer<Componente>(vv1
						.getPickedVertexState(), Color.red, Color.yellow));

		vv1.setVertexToolTipTransformer(new ToStringLabeller<Componente>());

		vv1.getRenderContext().setVertexLabelTransformer(
				new ToStringLabeller<Componente>());
		vv1.getRenderer().getVertexLabelRenderer().setPosition(
				Renderer.VertexLabel.Position.W);

		vv1.getRenderContext().setEdgeLabelTransformer(
				new ToStringLabeller<Ligacao>());

		graphMouse = new DefaultModalGraphMouse<Componente, Ligacao>();

		graphMouse.setMode(ModalGraphMouse.Mode.PICKING);

		vv1.setGraphMouse(graphMouse);

		satellite = new SatelliteVisualizationViewer<Componente, Ligacao>(vv1,
				new Dimension(600, 600));

		satellite.getRenderContext().setEdgeDrawPaintTransformer(
				new PickableEdgePaintTransformer<Ligacao>(satellite
						.getPickedEdgeState(), Color.black, Color.cyan));

		satellite.getRenderContext().setVertexFillPaintTransformer(
				new PickableVertexPaintTransformer<Componente>(satellite
						.getPickedVertexState(), Color.red, Color.yellow));

		ScalingControl satelliteScaler = new CrossoverScalingControl();

		satellite.scaleToLayout(satelliteScaler);

		grafo.removeVertex(comp);

		cl1 = new CachingLayout<Componente, Ligacao>(satellite.getGraphLayout());
		cl1.init();

		inicializaPosicoes(false);
		geraRepresPainel();

	}

	public void inicializaPosicoes(Boolean isIcon) {
		if (!isIcon) {
			for (Componente c : grafo.getVertices()) {
				if (c.getLocalVisual() != null) {
					satellite.getGraphLayout().setLocation(c,
							c.getLocalVisual());

				}
			}
			vv1.updateUI();
		} else {
			for (Componente c : grafo.getVertices()) {
				if (c.getLocalVisual() != null) {
					vv2.getGraphLayout().setLocation(c, c.getLocalVisual());

				}
			}
			vv2.updateUI();
		}

	}

	public Point2D getPosicao(Componente c, Boolean isIcon) {

		cl2.init();
		return cl2.transform(c);

		/*
		 * if (isIcon) { cl2.reset(); cl2.init(); return cl2.transform(c); }
		 * else { cl1.reset(); cl1.init(); return cl1.transform(c); }
		 */

	}

	private void geraRepresPainelIcon() {
		represPainelIcon = new JInternalFrameMod(viewPrinc);

		final GraphZoomScrollPane panel = new GraphZoomScrollPane(vv2);
		represPainelIcon.setIconifiable(false);
		represPainelIcon.setMaximizable(false);
		represPainelIcon.setResizable(false);
		represPainelIcon.setTitle(nome); // NOI18N
		represPainelIcon.setMinimumSize(new java.awt.Dimension(250, 300));
		represPainelIcon.setName("palcoInterno"); // NOI18N
		represPainelIcon.setVisible(true);

		represPainelIcon.setBounds(20, 20, 380, 390);

		represPainelIcon.getContentPane().add(panel);
		represPainelIcon.pack();
		represPainelIcon.setVisible(true);

		JComboBox modeBox = ((DefaultModalGraphMouse<Componente, Ligacao>) vv2
				.getGraphMouse()).getModeComboBox();

		this.viewSupport = new MagnifyImageLensSupport<Componente, Ligacao>(vv2);
		// new ViewLensSupport<Number,Number>(vv, new
		// HyperbolicShapeTransformer(vv,
		// vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.VIEW)),
		// new ModalLensGraphMouse());

		this.modelSupport = new LayoutLensSupport<Componente, Ligacao>(vv2);

		final DefaultModalGraphMouse graphMouse = (DefaultModalGraphMouse) vv2
				.getGraphMouse();
		graphMouse.addItemListener(modelSupport.getGraphMouse()
				.getModeListener());
		graphMouse.addItemListener(viewSupport.getGraphMouse()
				.getModeListener());

		JPanel p = new JPanel();

		p.add(modeBox);

		represPainelIcon.add(p, BorderLayout.SOUTH);

	}

	@SuppressWarnings("unchecked")
	private void geraRepresPainel() {

		GraphZoomScrollPane gzsp = new GraphZoomScrollPane(vv1);

		represPainel = new javax.swing.JInternalFrame();

		represPainel.setIconifiable(false);
		represPainel.setMaximizable(false);
		represPainel.setResizable(false);
		represPainel.setTitle(nome); // NOI18N
		represPainel.setMinimumSize(new java.awt.Dimension(250, 300));
		represPainel.setName("palcoInterno"); // NOI18N
		represPainel.setVisible(true);

		represPainel.setBounds(20, 20, 380, 390);

		represPainel.getContentPane().add(gzsp);

		represPainel.pack();
		represPainel.setVisible(true);

		JComboBox modeBox = ((DefaultModalGraphMouse<Componente, Ligacao>) vv1
				.getGraphMouse()).getModeComboBox();
		modeBox.addItemListener(((ModalGraphMouse) satellite.getGraphMouse())
				.getModeListener());
		JPanel p = new JPanel();

		p.add(modeBox);

		represPainel.add(p, BorderLayout.SOUTH);

	}

	public void addComponente(Componente componente) {

		

		// String name = SystemConstants.SYSTEM_ICONE_DIRECTORY +
		// componente.getNomeIcone();

		try {
			grafo.addVertex(componente);

			map.put(componente, componente.toString());

			File dirImagens = new File(SystemConstants.SYSTEM_ICONE_DIRECTORY);
			File[] arquivos = dirImagens.listFiles();

			File arqImg = null;
			for (File arq : arquivos) {
				StringTokenizer nomeArqBuf = new StringTokenizer(arq.getName(),
						".");
				String nomeSemExtensao = nomeArqBuf.nextToken();
				if (nomeSemExtensao == null) {
					nomeSemExtensao = arq.getName();
				}

				if (nomeSemExtensao.equalsIgnoreCase(componente.getNomeIcone())) {
					arqImg = arq;
				}

			}

			Image img = new ImageIcon(arqImg.getCanonicalPath()).getImage();

			Image newimg = img.getScaledInstance(60, 60,
					java.awt.Image.SCALE_SMOOTH);

			Icon icon = new LayeredIcon(newimg);

			iconMap.put(componente, icon);
			
			
			if(componente.getLocalVisual() != null){
				vv1.getGraphLayout().setLocation(componente,componente.getLocalVisual());
				vv2.getGraphLayout().setLocation(componente, componente.getLocalVisual());
			}
			vv1.updateUI();
			vv2.updateUI();
		} catch (Exception ex) {
			ex.printStackTrace();

		}

		

	}

	public void addLigacao(Ligacao ligacao) {

		grafo.addEdge(ligacao, ligacao.getOrigem(), ligacao.getDestino());
		vv1.updateUI();
		vv2.updateUI();
	}

	public Set<Componente> getComponentesSelecionados(Boolean isIcon) {

		return vv2.getPickedVertexState().getPicked();
		/*
		 * if (isIcon) { return vv2.getPickedVertexState().getPicked(); }
		 * 
		 * return vv1.getPickedVertexState().getPicked();
		 */

	}

	public Graph<Componente, Ligacao> getGrafo() {
		return grafo;
	}

	public void setGrafo(Graph<Componente, Ligacao> grafo) {
		this.grafo = grafo;
	}

	public String getNome() {
		return nome;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}

	public static void main(String[] args) {

		LensVertexImageShaperDemo demo = new LensVertexImageShaperDemo();

	}

	public JInternalFrame getRepresPainel(Boolean isIcon) {
		return represPainelIcon;

		/*
		 * if (isIcon) { return represPainelIcon; }else{ return represPainel; }
		 * 
		 */
	}

	public void setRepresPainel(JInternalFrame represPainel) {
		this.represPainel = represPainel;
	}

	public void editaNomePainel(String novoValor) {
		this.nome = novoValor;
		this.represPainel.setTitle(novoValor);

	}

	public void atualizaGrafo() {

		vv1.updateUI();
		vv2.updateUI();

	}

	public void removeComponente(Componente componente) {
		// TODO Auto-generated method stub

		grafo.removeVertex(componente);

		vv1.updateUI();
		vv2.updateUI();

	}

	public void removeLigacao(Ligacao l) {
		grafo.removeEdge(l);
		vv1.updateUI();
		vv2.updateUI();

	}

	
	class VertexStringerImpl<V> implements Transformer<V, String> {

		Map<V, String> map = new HashMap<V, String>();

		boolean enabled = true;

		public VertexStringerImpl(Map<V, String> map) {
			this.map = map;
		}

		/**
		 * @see edu.uci.ics.jung.graph.decorators.VertexStringer#getLabel(edu.uci.ics.jung.graph.Vertex)
		 */
		public String transform(V v) {
			if (isEnabled()) {
				return map.get(v);
			} else {
				return "";
			}
		}

		/**
		 * @return Returns the enabled.
		 */
		public boolean isEnabled() {
			return enabled;
		}

		/**
		 * @param enabled
		 *            The enabled to set.
		 */
		public void setEnabled(boolean enabled) {
			this.enabled = enabled;
		}
	}

	public static class PickWithIconListener implements ItemListener {
		DefaultVertexIconTransformer<Componente> imager;
		Icon checked;

		public PickWithIconListener(
				DefaultVertexIconTransformer<Componente> imager) {
			this.imager = imager;
			checked = new Checkmark(Color.red);
		}

		public void itemStateChanged(ItemEvent e) {
			Icon icon = imager.transform((Componente) e.getItem());
			if (icon != null && icon instanceof LayeredIcon) {
				if (e.getStateChange() == ItemEvent.SELECTED) {
					((LayeredIcon) icon).add(checked);
				} else {
					((LayeredIcon) icon).remove(checked);
				}
			}
		}
	}

	public void sincronizaPosicoes() {

		for (Componente c : grafo.getVertices()) {
			if (c.getLocalVisual() != null) {
				// System.out.println("teste");

				System.out.println("AT - " + c.getLocalVisual());
				vv1.getGraphLayout().setLocation(c, c.getLocalVisual());
				vv2.getGraphLayout().setLocation(c, c.getLocalVisual());

			}
		}
		// geraRepresPainel();
		// geraRepresPainelIcon();

		vv1.updateUI();

		vv2.updateUI();

	}

	public void atualizaPosicaoMg(Componente c, Point2D posicao) {

		vv1.getGraphLayout().setLocation(c, posicao);
		vv1.updateUI();

	}

	public void atualizaPosicaoMi(Componente c, Point2D posicao) {

		vv2.getGraphLayout().setLocation(c, posicao);
		vv2.updateUI();

	}

	public void atualizaMapa() {
		for (Componente componente : grafo.getVertices()) {
			map.put(componente, componente.toString());
		}
		vv2.updateUI();

	}

}
